package gamesys;

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;

import javax.swing.JOptionPane;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public abstract class GamePanel extends JPanel implements KeyListener
{
	private GraphicsDevice device;
	private BufferStrategy stratagy;
	private Graphics2D curGraphics;
	private Program parentFrame;
	private Canvas drawCanvas;
	private boolean useCanvas = true;
	
	public GamePanel(Program parentFrame)
	{
		this();
		this.parentFrame = parentFrame;
	}
	
	public GamePanel()
	{
		this.setLayout(new BorderLayout());
	}
	
	public final void intitialize(int numBuffers)
	{
		if(useCanvas)
		{
			drawCanvas = new Canvas();
			this.add(drawCanvas,BorderLayout.CENTER);
			drawCanvas.setVisible(true);
			boolean success = initDevice(numBuffers);
			drawCanvas.addKeyListener(this);
			if(!success)
				JOptionPane.showConfirmDialog(null, "Error could not start hardware acceleration");
		}
		intitialize();
		
	}
	
	protected void intitialize(){}
	
	private boolean initDevice(int numBuffers)
	{
		if(!drawCanvas.isVisible())
			return false;
		
		try{
			GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
			device = ge.getDefaultScreenDevice();
			drawCanvas.createBufferStrategy(numBuffers);
			stratagy = drawCanvas.getBufferStrategy();
		}
		catch(Exception ex){
			ex.printStackTrace();
			return false;
		}
		setIgnoreRepaint(true);
		return true;
	}
	
	public final void render()
	{
		Graphics2D g = beginPaint();
		render(g);
		endPaint();
	}
	
	protected abstract void render(Graphics2D g);
	
	private Graphics2D beginPaint()
	{
		if(stratagy != null)
			curGraphics = (Graphics2D)stratagy.getDrawGraphics();	
		return curGraphics;
	}
	
	private void endPaint()
	{
		if(curGraphics != null)
		   curGraphics.dispose();
		if(stratagy != null && !stratagy.contentsLost())
			stratagy.show();
		Toolkit.getDefaultToolkit().sync();
	}
	
	/**
	 * Tells the window to go full screen if able
	 */
	public boolean setFullScreen(boolean full)
	{
		if(device == null)
			return false; 
		boolean success = false;
		setVisible(false);
		
		parentFrame.dispose(); //we must dispose resources (and recreate) resources to go full screen
		
		if(device.isFullScreenSupported() && full){
			parentFrame.setUndecorated(true); //remove window border
			device.setFullScreenWindow(parentFrame);
			this.requestFocus(); //sometimes it could be full screen and not focused
			success = true;
		}
		else {
			parentFrame.setUndecorated(false);
			device.setFullScreenWindow(null);
		}
		setVisible(true);
	
		return success;
	}
	
	/**
	 * Returns all display modes compatible on current system.
	 */
	public DisplayMode[] getDisplayModes()
	{
		return device.getDisplayModes();
	}
	
	/**
	 * Sets a new display mode thats compatable with system
	 * @param newMode new mode to change to. This mode must be one of the modes from getDisplayModes.
	 * @return returns true if it successfully switched display modes false otherwise.
	 */
	public boolean setDisplayMode(DisplayMode newMode)
	{
		DisplayMode oldDisplay = device.getDisplayMode();

		try{
			if(device.isDisplayChangeSupported())
			   device.setDisplayMode(newMode);
		}
		catch(IllegalArgumentException ex) 
		{
			device.setDisplayMode(oldDisplay);
			return false;
		}
		return true;
	}
	
	public void setParentFrame(Program frame)
	{
		parentFrame = frame;
	}
	
	public void setPanel(GamePanel panel)
	{
		parentFrame.setPanel(panel);
	}
	
	protected void setUseCanvas(boolean bool)
	{
		this.useCanvas = bool;
	}
	

	public void keyPressed(KeyEvent e) 
	{
		if(e.getKeyCode() == KeyEvent.VK_ESCAPE)
			parentFrame.dispose(); //if this is the last window it sould terminate the program
	}

	public void keyReleased(KeyEvent e) 
	{
	}

	public void keyTyped(KeyEvent e) {}
	

}
